package com.dyh.quickdemo.demos.lbdand;

import lombok.extern.slf4j.Slf4j;

import java.util.function.Function;
import java.util.function.Predicate;

/*
@Author=Joey Wheeler
@Date=2020/12/8 9:48
*/
@Slf4j
public class FcBreaker<T, R> {
    String resourceName;
    Function<T, R> fc;
    Function<T,R> fallback;
    Predicate<R>[] fallbackTriggers;

    public static <T, R> Function<T, R> with(String resourceName,Function<T, R> fc,
                                             Function<T, R> fallback, Predicate<R> ...fallbackTriggers){
        FcBreaker fcBreaker = new FcBreaker();
        fcBreaker.fc =fc;
        fcBreaker.resourceName = resourceName;
        fcBreaker.fallbackTriggers = fallbackTriggers;


        return t->{
            boolean quickReturn = false;
            FcBreakerCenter.registIfAbsent(fcBreaker);
            FcBreakerCenter.startStatistics(fcBreaker);
            long start = TimeUtil.currentTimeMillis();
            R r;
            if (FcBreakerCenter.isCircuitBreaked(resourceName)){
                log.error("资源熔断resourceName={}",resourceName);
                r = fallback.apply(t);
                quickReturn = true;
            }
            else{
                r = fc.apply(t);
            }
            long diff = TimeUtil.currentTimeMillis()-start;
            FcBreakerCenter.collectMaxTime(resourceName,diff);
            FcBreakerCenter.endStatisticsIfTime(resourceName);
            if (quickReturn)
                return r;
            if (fallbackTriggers==null||fallbackTriggers.length==0){

            }
            else {
                for (Predicate<R> fallbackTrigger : fallbackTriggers) {
                    if (fallbackTrigger.test(r)){
                        FcBreakerCenter.circuitBreake(resourceName);//熔断
                        break;
                    }
                }
            }
            return r;
        };
    }
}
